package com.lt.system;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.Service;
import android.app.UiModeManager;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.os.Vibrator;
import android.text.TextUtils;
import android.view.View;
import android.view.inputmethod.InputMethodManager;

import com.lt.LibConstant;
import com.lt.base.BaseApplication;
import com.lt.common.DebugHelper;
import com.lt.view.ViewHelper;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Method;

public class SystemHelper {

    private static SystemHelper instance;

    private SystemHelper() {
    }

    public static SystemHelper getInstance() {
        if (instance == null) {
            synchronized (SystemHelper.class) {
                instance = new SystemHelper();
            }
        }
        return instance;
    }

    /**
     * 隐藏输入法
     */
    public boolean hideInput(Activity activity) {
        return hideInput(activity, activity.getCurrentFocus());
    }

    public boolean hideInput(Activity activity, View view) {
        InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
        return inputMethodManager != null && view != null && inputMethodManager.hideSoftInputFromWindow(view.getWindowToken(), 0);
    }

    /**
     * 打开输入法！
     */
    public void openInput(View view) {
        ViewHelper.getInstance().requestFocus(view);
        InputMethodManager inputManager = (InputMethodManager) view
                .getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
        if (inputManager != null) {
            inputManager.showSoftInput(view, InputMethodManager.RESULT_SHOWN);
        }
    }

    /**
     * 延时打开输入法！
     */
    public void openInput(final View view, final int time) {
        new Handler().postDelayed(() -> openInput(view), time);
    }


    /**
     * final Activity activity  ：调用该方法的Activity实例
     * long milliseconds ：震动的时长，单位是毫秒
     * long[] pattern  ：自定义震动模式 。数组中数字的含义依次是[静止时长，震动时长，静止时长，震动时长。。。]时长的单位是毫秒
     * boolean isRepeat ： 是否反复震动，如果是true，反复震动，如果是false，只震动一次
     */
    @SuppressLint("MissingPermission")
    public void Vibrate(final Activity activity, long milliseconds) {
        Vibrator vib = (Vibrator) activity.getSystemService(Service.VIBRATOR_SERVICE);
        if (vib != null) {
            vib.vibrate(milliseconds);
        }
    }

    @SuppressLint("MissingPermission")
    public void Vibrate(final Activity activity, long[] pattern, boolean isRepeat) {
        Vibrator vib = (Vibrator) activity.getSystemService(Service.VIBRATOR_SERVICE);
        if (vib != null) {
            vib.vibrate(pattern, isRepeat ? 1 : -1);
        }
    }

    /**
     * 发送短信<uses-permission android:name="android.permission.SEND_SMS" />
     */
    public void SendSMS(Context context, String SMStext) {
        Intent it = new Intent(Intent.ACTION_VIEW);
        it.putExtra("sms_body", SMStext);
        it.setType("vnd.android-dir/mms-sms");
        context.startActivity(it);
    }

    /**
     * 将号码传入拨打界面
     */
    public void callTel(String PhoneNum) {
        Intent intent = new Intent(Intent.ACTION_DIAL);
        intent.setData(Uri.parse("tel:" + PhoneNum));
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        try {
            BaseApplication.getContext().startActivity(intent);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * @return 获取android当前可用内存大小
     */
    public long getAvailMemory(Activity activity) {
        ActivityManager am = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);
        ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
        if (am != null) {
            am.getMemoryInfo(mi);
            //mi.availMem; 当前系统的可用内存
            return mi.availMem;// 将获取的内存大小规格化
        }
        return 0;
    }

    public long getTotalMemory() {
        String str1 = "/proc/meminfo";// 系统内存信息文件
        String str2;
        String[] arrayOfString;
        long initial_memory = 0;
        try {
            FileReader localFileReader = new FileReader(str1);
            BufferedReader localBufferedReader = new BufferedReader(
                    localFileReader, 8192);
            str2 = localBufferedReader.readLine();// 读取meminfo第一行，系统总内存大小
            arrayOfString = str2.split("\\s+");
            if (arrayOfString.length > 1) {
                initial_memory = Integer.valueOf(arrayOfString[1]).intValue() * 1024;// 获得系统总内存，单位是KB，乘以1024转换为Byte
            }
            localBufferedReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return initial_memory;
    }

    public boolean isAndroidTV(Context ctx) {
        final UiModeManager uiModeManager = (UiModeManager) ctx.getSystemService(Activity.UI_MODE_SERVICE);
        return uiModeManager != null && uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION;
    }

    /**
     * @return 判断GPS是否打开
     */
    public boolean isGpsOpen() {
        LocationManager locationManager = (LocationManager) BaseApplication.getContext().getSystemService(Context.LOCATION_SERVICE);
        return locationManager != null && locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
    }

    public boolean copy2Clipboard(String str) {
        //获取剪贴板管理器：
        ClipboardManager cm = (ClipboardManager) BaseApplication.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
        if (TextUtils.isEmpty(str) || cm == null) {
            return false;
        }
        // 创建普通字符型ClipData
        ClipData mClipData = ClipData.newPlainText("Label", str);
        // 将ClipData内容放到系统剪贴板里。
        cm.setPrimaryClip(mClipData);
        return true;
    }

    /**
     * @return 是否有安装权限
     */
    public boolean isCanInstalls(Activity act) {
        return Build.VERSION.SDK_INT < 26 || act.getPackageManager().canRequestPackageInstalls();
    }

    public void chmod(String path) {
        String[] command = {"chmod", "777", path};
        ProcessBuilder builder = new ProcessBuilder(command);
        try {
            builder.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    /**
     * 通过反射机制查询系统配置
     */
    @SuppressLint("PrivateApi")
    public String getAndroidOsSystemProperties(String key) {
        Method systemProperties_get = null;
        String ret;
        try {
            systemProperties_get = Class.forName("android.os.SystemProperties").getMethod("get",
                    String.class);
            if ((ret = (String) systemProperties_get.invoke(null, key)) != null)
                return ret;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return "";
    }

    /**
     * 获取SN
     */
    @SuppressLint("MissingPermission")
    public String getSn() {
        String result = null;
        result = Build.SERIAL;
        if (!TextUtils.isEmpty(result)) {
            return result;
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            try {
                result = Build.getSerial();
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {
            result = Build.SERIAL;
        } else {
            result = getAndroidOsSystemProperties("ro.boot.serialno");
            if (TextUtils.isEmpty(result)) {
                result = getAndroidOsSystemProperties("ro.serialno");
            }
        }
        return TextUtils.isEmpty(result) ? LibConstant.unknown : result;
    }


    /**
     * 获取SN
     */
    @SuppressLint("MissingPermission")
    public String getSN_V2() {
        String serial = LibConstant.unknown;
        //通过android.os获取sn号
        try {
            serial = Build.SERIAL;
            if (!TextUtils.isEmpty(serial) && !serial.equals(LibConstant.unknown)) return serial;
        } catch (Exception e) {
            e.printStackTrace();
        }

        //通过反射获取sn号
        try {
            Class<?> c = Class.forName("android.os.SystemProperties");
            Method get = c.getMethod("get", String.class);
            serial = (String) get.invoke(c, "ro.serialno");
            if (!TextUtils.isEmpty(serial) && !serial.equals(LibConstant.unknown)) return serial;
            //9.0及以上无法获取到sn，此方法为补充，能够获取到多数高版本手机 sn
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) serial = Build.getSerial();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return serial;
    }

    /**
     * 执行 adb 命令
     *
     * @param cmd 命令
     * @return 结果
     */
    public StringBuffer shellExec(String cmd) {
        Runtime mRuntime = Runtime.getRuntime(); //执行命令的方法
        try {
            //Process中封装了返回的结果和执行错误的结果
            Process mProcess = mRuntime.exec(cmd); //加入参数
            //使用BufferReader缓冲各个字符，实现高效读取
            //InputStreamReader将执行命令后得到的字节流数据转化为字符流
            //mProcess.getInputStream()获取命令执行后的的字节流结果
            BufferedReader mReader = new BufferedReader(new InputStreamReader(mProcess.getInputStream()));
            //实例化一个字符缓冲区
            StringBuffer mRespBuff = new StringBuffer();
            //实例化并初始化一个大小为1024的字符缓冲区，char类型
            char[] buff = new char[1024];
            int ch = 0;
            //read()方法读取内容到buff缓冲区中，大小为buff的大小，返回一个整型值，即内容的长度
            //如果长度不为null
            while ((ch = mReader.read(buff)) != -1) {
                //就将缓冲区buff的内容填进字符缓冲区
                mRespBuff.append(buff, 0, ch);
            }
            //结束缓冲
            mReader.close();
            DebugHelper.w("shell", "shellExec: " + mRespBuff);
            //弹出结果
//            Log.i("shell", "执行命令: " + cmd + "执行成功");
            return mRespBuff;
        } catch (IOException e) {
            // 异常处理
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 执行 adb 命令
     *
     * @param commands 命令数组
     * @return 结果
     */
    public StringBuffer shellExecSu(String[] commands) {
        Runtime mRuntime = Runtime.getRuntime(); //执行命令的方法
        try {
            //Process中封装了返回的结果和执行错误的结果
            Process mProcess = mRuntime.exec("su"); //加入参数

            DataOutputStream os = new DataOutputStream(mProcess.getOutputStream());
            for (String cmd : commands) {
                os.writeBytes(cmd + "\n");
                os.flush();
            }
            os.writeBytes("exit\n");
            os.flush();

            //使用BufferReader缓冲各个字符，实现高效读取
            //InputStreamReader将执行命令后得到的字节流数据转化为字符流
            //mProcess.getInputStream()获取命令执行后的的字节流结果
            BufferedReader mReader = new BufferedReader(new InputStreamReader(mProcess.getInputStream()));
            //实例化一个字符缓冲区
            StringBuffer mRespBuff = new StringBuffer();
            //实例化并初始化一个大小为1024的字符缓冲区，char类型
            char[] buff = new char[1024];
            int ch = 0;
            //read()方法读取内容到buff缓冲区中，大小为buff的大小，返回一个整型值，即内容的长度
            //如果长度不为null
            while ((ch = mReader.read(buff)) != -1) {
                //就将缓冲区buff的内容填进字符缓冲区
                mRespBuff.append(buff, 0, ch);
            }
            //结束缓冲
            mReader.close();
            DebugHelper.w("shell", "shellExec: " + mRespBuff);
            //弹出结果
//            Log.i("shell", "执行命令: " + cmd + "执行成功");
            return mRespBuff;
        } catch (IOException e) {
            // 异常处理
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    public String runCommand(String command) {
        Process process = null;
        String result = "";
        DataOutputStream os = null;
        DataInputStream is = null;
        try {
            process = Runtime.getRuntime().exec("su");
            os = new DataOutputStream(process.getOutputStream());
            is = new DataInputStream(process.getInputStream());
            os.writeBytes(command + "\n");
            os.writeBytes("exit\n");
            os.flush();
            String line = null;
            while ((line = is.readLine()) != null) {
                result += line;
            }
            process.waitFor();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (os != null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (process != null) {
                process.destroy();
            }
        }
        return result;
    }


    /**
     * 通过类对象，运行指定方法
     *
     * @param obj        类对象
     * @param methodName 方法名
     * @param params     参数值
     * @return 失败返回null
     */
    public Object invokeDeclaredMethod(Object obj, String methodName, Object[] params) {
        if (obj == null || TextUtils.isEmpty(methodName)) {
            return null;
        }
        Class<?> clazz = obj.getClass();
        try {
            Class<?>[] paramTypes = null;
            if (params != null) {
                paramTypes = new Class[params.length];
                for (int i = 0; i < params.length; ++i) {
                    paramTypes[i] = params[i].getClass();
                }
            }
            Method method = clazz.getDeclaredMethod(methodName, paramTypes);
            method.setAccessible(true);
            return method.invoke(obj, params);
        } catch (NoSuchMethodException e) {
            DebugHelper.d("reflect", "method " + methodName + " not found in " + obj.getClass().getName());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}